package com.kly.chatter.api.application.controller.chatter;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.nacos.api.config.annotation.NacosValue;
import com.fqgj.common.api.Page;
import com.fqgj.common.api.Response;
import com.fqgj.common.api.annotations.ParamsValidate;
import com.fqgj.common.utils.CollectionUtils;
import com.fqgj.log.factory.LogFactory;
import com.fqgj.log.interfaces.Log;
import com.jsoniter.output.JsonStream;
import com.kly.chatter.api.application.config.NacosValueConfig;
import com.kly.chatter.api.application.controller.chatter.req.*;
import com.kly.chatter.api.application.controller.chatter.req.ChatterModelsUnreadMsgReq;
import com.kly.chatter.api.application.controller.chatter.res.ChatterModelsUnreadMsgRes;
import com.kly.chatter.api.application.controller.chatter.res.InterestsRes;
import com.kly.chatter.api.application.controller.chatter.res.ModelsRsp;
import com.kly.chatter.api.application.controller.chatter.res.TurnOnsRes;
import com.kly.chatter.api.application.dto.ChatterRewardReq;
import com.kly.chatter.api.application.dto.ChatterRewardResp;
import com.kly.chatter.api.application.service.*;
import com.kly.chatter.api.application.utils.Result;
import com.kly.sc.api.application.annos.SignIgnore;
import com.kly.sc.api.application.annos.VisitorAccessible;
import com.kly.sc.api.application.constant.ApiRedisKeys;
import com.kly.sc.api.application.consts.Constants;
import com.kly.sc.api.application.enums.ApiResultStatus;
import com.kly.sc.api.application.helper.RequestLocalInfo;
import com.kly.sc.api.application.utils.RpcUtils;
import com.kly.sc.api.infras.enums.RestCodeEnum;
import com.kly.sc.api.infras.exception.ApplicationException;
import com.kly.sc.api.integration.im.IMService;
import com.kly.sc.api.integration.im.RCClient;
import com.kly.user.chatterService.ChatService;
import com.kly.user.chatterService.GreetingService;
import com.kly.user.chatterService.ModelService;
import com.kly.user.dto.*;
import com.kly.user.dto.chatter.request.ConversationOPReq;
import com.kly.user.dto.chatter.request.ConversationReq;
import com.kly.user.dto.chatter.request.QueryModelReq;
import com.kly.user.dto.chatter.response.ChatterModelsUnreadMsgDto;
import com.kly.user.dto.chatter.response.ChatterModelsUnreadMsgDtoItem;
import com.kly.user.dto.chatter.response.ModelsDto;
import com.kly.user.dto.chatter.response.UserGreetingContentDto;
import com.kly.user.enums.AppEnum;
import com.kly.user.enums.RememberTime;
import com.kly.user.enums.UserTokenType;
import com.kly.user.service.*;
import io.rong.messages.TxtMessage;
import io.rong.models.message.PrivateMessage;
import io.rong.models.response.ResponseResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author linqu
 */
@RestController
@RequestMapping("/api/chat")
@Api(value = "chatter操作相关接口", tags = {"chatter操作相关接口"})
public class ChatController {

    @Resource
    ChatService chatService;

    private static final Log logger = LogFactory.getLog(ChatController.class);
    @Resource
    ModelService modelService;
    @Resource
    GreetingService greetingService;
    @Resource
    RCClient rcClient;
    @Resource
    AuthLoginService authLoginService;
    @Resource
    IMService imService;
    @Resource
    OtherService otherService;
    @Resource
    WlmService wlmService;
    @Resource
    RedisService redisService;
    @Resource
    AsyncSendMsgService asyncSendMsgService;

    @Resource
    InterestService interestService;

    @Resource
    UserService userService;
    @Resource
    ChatterRewardService chatterRewardService;

    @Autowired
    private ChatterModelInfoExamineService chatterModelInfoExamineService;

    @Autowired
    private ChatterImRewardService chatterImRewardService;

    @Autowired
    private NacosValueConfig nacosValueConfig;

    @Autowired
    private UserMsgService userMsgService;

    /**
     * modelList接口是否关闭，默认关闭
     */
    @NacosValue(value = "${modelList.api.enable.switch:false}", autoRefreshed = true)
    private Boolean modelListApiEnableSwitch;


    /**
     * model列表接口
     */
    @ApiOperation("chat页面model展示接口")
    @RequestMapping(value = "/modelList", method = {RequestMethod.POST})
    @SentinelResource
    public Response newMatchList(@Valid @RequestBody QueryModelRequest request, BindingResult results) {
        if (modelListApiEnableSwitch) {
            return Response.ok();
        }

        if (results.hasErrors()) {
            return Response.error();
        }

        final QueryModelReq queryModelReq = QueryModelReq.builder().chatterUserCode(request.getChatterUserCode()).modelUserCode(request.getModelUserCode()).build();
        final ModelsDto result = RpcUtils.getResult(modelService.queryModelList(queryModelReq));

        final List<com.kly.user.dto.chatter.response.ChatUser> modelList = result.getModelList();
        if (CollectionUtils.isNotEmpty(modelList)) {
            final List<com.kly.user.dto.chatter.response.ChatUser> newModelList = modelList.stream().peek(o -> {
                if (o.getModelAccount() != null && StringUtils.isEmpty(o.getModelAccount().getToken())) {
                    o.getModelAccount().setToken(validateAndSaveToken(o.getModelAccount().getUserCode()));
                }
            }).collect(Collectors.toList());

            result.setModelList(newModelList);
        }

        return Response.ok(ModelsRsp.toModelRsp(result).setNews(nacosValueConfig.platformChatListNews()));
    }

    @ApiOperation("chat页面model展示接口")
    @RequestMapping(value = "/modelListV2", method = {RequestMethod.POST})
    @SentinelResource
    public Response chatterModelsUnreadMsg() {
        logger.info("==chatterModelsUnreadMsg 找到的数据为空 开始: chatterCode:{}", RequestLocalInfo.getCurrentUser().getUserCode());
        Response<ChatterModelsUnreadMsgDto> chatterModelsUnreadMsgInfo = modelService.getChatterModelsUnreadMsgInfo(RequestLocalInfo.getCurrentUser().getUserCode());
//        Response<ChatterModelsUnreadMsgDto> chatterModelsUnreadMsgInfo = modelService.getChatterModelsUnreadMsgInfo("297185968153281770");
        logger.info("==chatterModelsUnreadMsg 找到的数据为空 找到model ==,size:{}", chatterModelsUnreadMsgInfo.getData().getModels().size());

        List<ChatterModelsUnreadMsgDtoItem> modelsFinal = new ArrayList<>();
        List<ChatterModelsUnreadMsgDtoItem> models = chatterModelsUnreadMsgInfo.getData().getModels();
        models.forEach(m -> {
            if (StringUtils.isEmpty(m.getToken())) {
                logger.info("==chatterModelsUnreadMsg  model没有融云token,现在重新生成 ==,model:{}", m.getModelCode());
                try {
                    String token = imService.getToken(m.getModelCode(), m.getNickName(), m.getAvatarUrl());
                    m.setToken(token);
                    modelsFinal.add(m);
                } catch (Exception e) {
                    logger.error("==chatterModelsUnreadMsg  model没有融云token,现在重新生成 重新生成错误 ==,model:{}", m.getModelCode(), e);
                }
            } else {
                modelsFinal.add(m);
            }
        });

//        return Response.ok(ModelsRsp.toModelRsp(result).setNews(nacosValueConfig.platformChatListNews()));
        return Response.ok(new ChatterModelsUnreadMsgRes(modelsFinal).setNews(nacosValueConfig.platformChatListNews()));
    }

    @ApiOperation("打招呼")
    @RequestMapping(value = "/sayHi", method = {RequestMethod.POST})
    @ParamsValidate
    @SentinelResource
    public Response sayHi(@RequestBody ModelUserCodeListReq modelUserCodeListReq) {

        final String chatterUserCode = RequestLocalInfo.getCurrentUser().getUserCode();
        // 获取招呼语
        final List<UserGreetingContentDto> greetingContentDtos = RpcUtils.getResult(greetingService.queryByChatterUserCode(modelUserCodeListReq.getChatterUserCode()));
        if (CollectionUtils.isEmpty(greetingContentDtos)) {
            return Response.error("The models has not set greetings.");
        }
        final List<ChatUser> chatUsers = modelUserCodeListReq.getChatUsers();
        for (ChatUser o : chatUsers) {
            // 检查当前用户在IM平台是否完成注册
            validateAndSaveToken(o.getModelUserCode());
            // 检查目标用户在IM平台是否完成注册
            validateAndSaveToken(o.getChatUserCode());
            // 保存一条对方用户的会话（非当前用户）
            final String content = greetingContentDtos.parallelStream().filter(o1 -> o1.getModelUserCode().equalsIgnoreCase(o.getModelUserCode())).findAny().map(UserGreetingContentDto::getGreetingContent).orElse("");

            final ConversationReq conversationReq = ConversationReq.builder().fromUserCode(o.getModelUserCode()).toUserCode(o.getChatUserCode()).chatterUserCode(chatterUserCode).type(1).source(AppEnum.MECHAT.getAppCode()).latestMsg(content).latestTime(new Date()).conversationType(1).build();
            final com.fqgj.common.api.Response response = chatService.storageConversation(conversationReq);
            if (Objects.nonNull(response) && response.isSuccess()) {
                // 异步发送消息
                asyncSendMsgService.sendMsg(o.getModelUserCode(), "PRIVATE", o.getChatUserCode(), "RC:TxtMsg", content, content, chatterUserCode, 0, null);
            }
        }

        return Response.ok();
    }


    private String validateAndSaveToken(String currentUserCode) {
        final String currentUserToken = RpcUtils.getResult(authLoginService.getRongCloudToken(currentUserCode));
        if (StringUtils.isBlank(currentUserToken)) {
            final UserInfoDto userInfoDto = RpcUtils.getResult(userService.getUserByUserCode(currentUserCode));
            if (Objects.nonNull(userInfoDto) && StringUtils.isNotBlank(userInfoDto.getNickName()) && StringUtils.isNotBlank(userInfoDto.getAvatarUrl())) {
                return imService.getToken(currentUserCode, userInfoDto.getNickName(), userInfoDto.getAvatarUrl());
            }
            throw new ApplicationException("Add IM token failed, userCode:" + currentUserCode);
        }
        return currentUserToken;
    }

    /**
     * 通过后端api发送消息时， 将chatterUserCode 暂时存放在 groupUserIds中
     */
    public void sendMessage(String currentUserId, String conversationType, String targetId, String objectName, String content, String pushContent, String chatterUserCode) throws ApplicationException {

        ResponseResult responseResult = null;
        if (Constants.CONVERSATION_TYPE_PRIVATE.equals(conversationType)) {
            PrivateMessage privateMessage = new PrivateMessage().setSenderId(currentUserId)
                    // 是否向发件人客户端同步已发消息。1 表示同步 0，即不同步
                    .setIsIncludeSender(1).setTargetId(new String[]{targetId}).setObjectName(objectName).setContent(new TxtMessage(content, "")).setPushContent(pushContent);
            responseResult = rcClient.sendPrivateMessage(privateMessage);
        }


        if (Objects.isNull(responseResult) || responseResult.getCode() != 200) {
            logger.error("Send message by IM exception, resultCode={},errorMessage={}", responseResult.getCode(), responseResult.getErrorMessage());
            throw new ApplicationException(RestCodeEnum.RC_PARAMETER_ERROR + " errorMsg: " + responseResult.getErrorMessage());
        }

        final AddMessageReq addMessageReq = AddMessageReq.builder().msgUID(responseResult.getRequestId()).fromUserId(currentUserId).toUserId(targetId).objectName("RC:TxtMsg").content(content).source("Server").groupUserIds(chatterUserCode).build();
        otherService.addMessage(addMessageReq);


    }

    @ApiOperation("离开聊天页面接口")
    @RequestMapping(value = "/leaveChat", method = {RequestMethod.POST})
    @SentinelResource
    public Response leaveChat(@RequestBody ConversationOPReq req) {
        if (StringUtils.isEmpty(req.getModelUserCode()) || StringUtils.isEmpty(req.getUserCodeFriend())) {
            throw new ApplicationException(ApiResultStatus.USER_AND_MODEL_CODE_EMPTY);
        }
        final String userCode = RequestLocalInfo.getCurrentUser().getUserCode();

        // 未读消息更新为已读
        chatService.readMsg(req.getUserCodeFriend(), req.getModelUserCode(), userCode);

        // 保存一条对方用户的会话（非当前用户）
        final ConversationReq conversationReq = ConversationReq.builder().fromUserCode(req.getModelUserCode()).toUserCode(req.getUserCodeFriend()).chatterUserCode(userCode).type(req.getType()).source(AppEnum.MECHAT.getAppCode()).latestTime(new Date()).conversationType(1).build();
        chatService.storageConversation(conversationReq);

        return Response.ok();

    }

    @ApiOperation("添加FCM会话token")
    @ResponseBody
    @RequestMapping(value = "/addPushToken", method = {RequestMethod.POST})
    @SentinelResource
    public Response addPushToken(@Valid @RequestBody PushTokenRequest pushTokenRequest, BindingResult results) {

        String userCode = RequestLocalInfo.getCurrentUser().getUserCode();
        if (results.hasErrors()) {
            return Response.error(results.getAllErrors().get(0).getDefaultMessage());
        }
        UserTokenType byCode = UserTokenType.getByCode(pushTokenRequest.getSourceType());
        if (byCode == null) {
            return Response.error(ApiResultStatus.INVALID_SOURCE_TYPE);
        }
        UserAccessDto userAccessDto = new UserAccessDto();
        userAccessDto.setToken(pushTokenRequest.getToken());
        userAccessDto.setUserCode(userCode);
        authLoginService.saveToken(userAccessDto, byCode);

        redisService.setString(ApiRedisKeys.USER_FIREBASE_TOKEN.getValue(), pushTokenRequest.getToken(), RememberTime.ONE_WEEK.getTime(), userCode);
        return Response.ok();
    }

    @ResponseBody
    @RequestMapping(value = "/addPush", method = {RequestMethod.POST})
    @SentinelResource
    public Response addPushToken(@RequestBody PushTokenRequest pushTokenRequest, String userCode) {
        redisService.setString(ApiRedisKeys.USER_FIREBASE_TOKEN.getValue(), pushTokenRequest.getToken(), RememberTime.ONE_WEEK.getTime(), userCode);
        redisService.addDelayTask(ApiRedisKeys.USER_OPERATION_INTERVAL.getValue(), userCode, 0L, "userOperationInterval");
        return Response.ok();
    }


    @GetMapping("/turnOns")
    @SentinelResource
    @ApiOperation(value = "turnOns字典", notes = "turnOns字典")
    public Result<List<TurnOnsRes>> turnOns() {
        List<UserTurnOnsDto> userTurnOnsDtoList = userService.getuserTurnOnsList();
        return Result.ok(TurnOnsRes.toTurnOnsRes(userTurnOnsDtoList));
    }

    @GetMapping("/interests")
    @ApiOperation(value = "interests字典", notes = "interests字典")
    @SentinelResource
    public Result<List<InterestsRes>> interests() {
        List<InterestDto> interestDtoList = RpcUtils.getResult(interestService.getAll());
        return Result.ok(InterestsRes.toInterestsRes(interestDtoList));
    }

    @PostMapping("/edit")
    @ApiOperation(value = "chatter下model信息修改", notes = "interests字典")
    @SentinelResource
    public Result edit(@RequestBody ChatterEditReq chatterEditReq) {
        userService.editModelInfo(ChatterEditReq.toModelInfoChangeDto(chatterEditReq));
        if (!StringUtils.isEmpty(chatterEditReq.getAboutMe())) {
            chatterModelInfoExamineService.add(chatterEditReq);
        }
        return Result.ok(chatterEditReq);
    }


    @GetMapping("/sendNotice")
    @ApiOperation(value = "会话通知", notes = "会话通知")
    @SentinelResource
    public Result sendNotice(@RequestParam String modelUserCode, @RequestParam String chatUserCode, @RequestParam String chatterUserCode) {
        List<String> messageList = new ArrayList<>();
        messageList.add(String.valueOf(3));
        messageList.add("$" + 11);
        String message = String.format("User sends %s more messages and you get rewarded with $%s!", 3, "11");
        asyncSendMsgService.sendMsg(chatUserCode, "message", modelUserCode, "RC:InfoNtf", message, message, chatterUserCode, 1, messageList);
        return Result.ok();
    }

    @SignIgnore
    @VisitorAccessible
    @PostMapping("/reward/list")
    @ApiOperation(value = "chatter工资列表查询", notes = "chatter工资列表查询")
    @SentinelResource
    public Result rewardList(@RequestBody ChatterRewardReportReq chatterRewardReportReq) {
        ChatterRewardReq rewardReq = new ChatterRewardReq();
        BeanUtils.copyProperties(chatterRewardReportReq, rewardReq);
        final ChatterRewardResp chatterRewardResp = chatterRewardService.listChatterReward(rewardReq, new Page(chatterRewardReportReq.getPageSize(), chatterRewardReportReq.getCurrent()));
        return Result.ok(chatterRewardResp);
    }

    @SignIgnore
    @VisitorAccessible
    @PostMapping("/sendMessageNotice")
    @SentinelResource
    public Result sendMessageNotice(@RequestBody MessageNoticeReq messageNoticeReq) {
        chatterImRewardService.sendMessageNotice(messageNoticeReq);
        return Result.ok();
    }

    @SignIgnore
    @VisitorAccessible
    @PostMapping("/sendVipMessageNotice")
    @ApiOperation(value = "vip提醒", notes = "vip提醒")
    @SentinelResource
    public Result sendVipMessageNotice(@RequestBody MessageVipNoticeReq messageVipNoticeReq) {

        chatterImRewardService.sendVipMessageNotice(messageVipNoticeReq);
        return Result.ok();
    }


    @PostMapping("/switch/model/notify")
    @ApiOperation(value = "切换model时候通知后端", notes = "切换model时候通知后端")
    @SentinelResource
    public Result switchModelNotify(@RequestBody SwitchModelNotifyReq switchModelNotifyReq) {

        logger.info("==switchModelNotify  ==,请求参数:{}", JsonStream.serialize(switchModelNotifyReq));
        MsgUnreadVo msgUnreadVo = new MsgUnreadVo().setUnreadMsgOfFromModel(switchModelNotifyReq.getUnreadMsgOfFromModel()).setFromModel(switchModelNotifyReq.getFromModel()).setChatterCode(RequestLocalInfo.getCurrentUser().getUserCode()).setTimestamp(switchModelNotifyReq.getTimestamp());
        userMsgService.recordModelSwitchUnreadMsg(msgUnreadVo);
        return Result.ok();
    }


}
